#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>

using namespace std;
const static int defaultcap=5;


template <class T>
class RingQueue
{
public:
    void P(sem_t& sem)
    {
        sem_wait(&sem);//用信号量
    }

    void V(sem_t& sem)
    {
        sem_post(&sem);//去信号量
    }

    void Lock(pthread_mutex_t& mutex_)
    {
        pthread_mutex_lock(&mutex_);
    }

    void Unlock(pthread_mutex_t& mutex_)
    {
        pthread_mutex_unlock(&mutex_);
    }

    RingQueue(int cap=defaultcap)
    :cap_(cap),ringqueue(cap),p_step(0),c_step(0)
    {
        sem_init(&cdata_sem,0,0);
        sem_init(&pdata_sem,0,cap_);

        pthread_mutex_init(&c_mutex,nullptr);
        pthread_mutex_init(&p_mutex,nullptr);
    }

    void Push(const T& in)
    {
        P(pdata_sem);
        Lock(p_mutex);

        ringqueue[p_step]=in;
        p_step++;
        p_step%=cap_;

        Unlock(p_mutex);
        V(cdata_sem);
    }

    T Pop()
    {
        P(cdata_sem);
        Lock(c_mutex);

        T out=ringqueue[c_step];
        c_step++;
        c_step%=cap_;

        Unlock(c_mutex);
        V(pdata_sem);//生产资源变大
        
        return out;
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&p_mutex);
        pthread_mutex_destroy(&c_mutex);

        sem_destroy(&cdata_sem);
        sem_destroy(&pdata_sem);
    }

private:
    std::vector<T> ringqueue;
    int cap_;

    int p_step;//生产者下标
    int c_step;//消费者下标 ，哪里取数据

    sem_t cdata_sem;//消费者可用资源
    sem_t pdata_sem;

    pthread_mutex_t c_mutex;
    pthread_mutex_t p_mutex;
};